#include "precomp.h"
#include "EntityUnitStats.h"
#include "../Entity.h"

namespace Tmpl {

#define ENTITY_STATS_JOBS 8

static DataValuePool<EntityUnitStats> gStats;

// EntitUnityStatSystem setup functions
void EntityUnitStatSystem::Init()
{
	gStats.Init();
}
void EntityUnitStatSystem::Clear()
{
	gStats.Clear();
}
int EntityUnitStatSystem::NewStats(Entity* owner, const UnitData& data)
{
	int id = gStats.NewValue();

	EntityUnitStats* value = gStats.GetValue(id);
	value->mOwner = owner;
	value->mHP = value->mHPMax = data.unit.hp;
	value->mConditionFlags = EntityUnitStats::UNIT_CONDITION_ALIVE;

	return id;
}
void EntityUnitStatSystem::RemoveStats(int id)
{
	gStats.RemoveValue(id);
}
EntityUnitStats* EntityUnitStatSystem::GetStats(int id)
{
	return gStats.GetValue(id);
}
// EntityUnitStats
void EntityUnitStats::AddHP(float hp, int entitySource)
{
	mHP += hp;

	// Kill unit if hp drops below 0
	if (mHP < 0.0f && ConditionHasFlag(UNIT_CONDITION_ALIVE))
	{
		ConditionRemoveFlag(UNIT_CONDITION_ALIVE);
		ConditionAddFlag(UNIT_CONDITION_DEAD);

		// perhaps send a message to the killer?
	}

	// Clamp it
	mHP = Clamp(0.0f, mHPMax, mHP);
}
// Updating
void EntityUnitStatSystem::UpdateStatsChunk(int chunk)
{
	int count = gStats.GetValueCount();
	int step = count / ENTITY_STATS_JOBS;
	int from = step * chunk;
	int to = ((chunk==ENTITY_STATS_JOBS-1) ? count : step * (chunk+1));
	for (int i=from; i<to; ++i)
	{
		EntityUnitStats* v = gStats.GetUnmappedValue(i);
		Entity* ent = v->mOwner;

		// Ensure HP cap
		if (v->mHP > v->mHPMax)	v->mHP = v->mHPMax;

		// play death animation and remove
		if (v->IsDead())
		{
			ent->Kill();
		}
	}
}
JobHandle EntityUnitStatSystem::Update(JobHandle dependency)
{
	JobHandle statsUpdate = JobManager::NewJob();
	for (int i=0; i<ENTITY_STATS_JOBS; ++i)
	{
		JobHandle job = JobManager::NewJob(&EntityUnitStatSystem::UpdateStatsChunk,i);
		JobManager::AddJobDependency(job, dependency);
		JobManager::AddExecuteJob(job);

		JobManager::AddJobDependency(statsUpdate, job);
	}
	JobManager::AddExecuteJob(statsUpdate);

	return statsUpdate;
}
}